<script lang="ts">
    import {bem} from "@/common/util";
    import mixin from "@/uni_modules/u-tools/mixin/mixin";
    import mpMixin from "@/uni_modules/u-tools/mixin/mpMixin";
    import props from "./props";
    import UIcon from "@/uni_modules/u-icon/components/u-icon/u-icon.vue";
    import UText from "@/uni_modules/u-text/components/u-text/u-text.vue";

    export default {
        name: "u-input",
        // 组件
        components: {UIcon, UText},
        // 混合
        mixins: [props, mixin, mpMixin],
        // 事件
        emits: ["update:value", "input", "focus", "blur", "confirm", "keyboardHeightChange", "onload", "clear"],
        // 数据
        data()
        {
            return {
                // 当前输入框的值
                inputValue: "",
                // 输入框是否获取焦点
                isFocus: false
            };
        },
        // 监听器
        watch: {
            // 监听输入框的值
            value(value: string | number | null): void
            {
                this.inputValue = value != null ? value.toString() : "";
            }
        },
        // 页面挂载
        mounted()
        {
            // 组件挂载完成
            this.$nextTick(() =>
            {
                // 获取当前输入框的值
                this.inputValue = this.value != null ? this.value.toString() : "";

                // 当前的值
                const outputValue = this.getOutputValue();

                // 判断是否触发input事件
                if (this.trigger)
                {
                    // 触发自定义input事件
                    this.$emit("input", outputValue);
                }

                // 触发onload事件
                this.$emit("onload", outputValue);
            });
        },
        // 计算函数
        computed: {
            // 生成bem风格的类名
            bemClass(): string
            {
                return bem("input", [
                    this.size,
                    this.shape,
                    `border-${this.border}`,
                    this.disabled ? "disabled" : "",
                    this.shape === "square" && SizeTypeMap.includes(this.radius.toString()) ? `radius-${this.radius}` : ""
                ]);
            },
            // 获取按钮圆角
            getRadius(): string
            {
                let radius = "";

                // 判断是否为方形按钮
                if (this.shape === "square")
                {
                    // 判断是否为指定大小的圆角
                    if (!SizeTypeMap.includes(this.radius.toString()))
                    {
                        radius = this.$u.unit(this.radius);
                    }
                }

                return radius;
            },
            // 获取输入框字体大小
            getFontSize(): string
            {
                let size = this.fontSize;

                // 如果为auto，则根据当前尺寸动态设置
                if (size === "auto")
                {
                    // 大尺寸
                    if (this.size === "large")
                    {
                        size = 16;
                    }
                    // 普通尺寸
                    if (this.size === "normal")
                    {
                        size = 16;
                    }
                    // 小尺寸
                    else if (this.size === "small")
                    {
                        size = 14;
                    }
                    // 超小尺寸
                    else if (this.size === "mini")
                    {
                        size = 12;
                    }
                }

                return this.$u.unit(size);
            },
            // 获取前缀图标大小
            getPrefixIconSize(): string | number
            {
                let size = this.prefixIconSize;

                // 如果为auto，则根据当前尺寸动态设置
                if (size === "auto")
                {
                    // 大尺寸
                    if (this.size === "large")
                    {
                        size = 18;
                    }
                    // 普通尺寸
                    if (this.size === "normal")
                    {
                        size = 16;
                    }
                    // 小尺寸
                    else if (this.size === "small")
                    {
                        size = 14;
                    }
                    // 超小尺寸
                    else if (this.size === "mini")
                    {
                        size = 12;
                    }
                }

                return size;
            },
            // 获取后缀图标大小
            getSuffixIconSize(): string | number
            {
                let size = this.suffixIconSize;

                // 如果为auto，则根据当前尺寸动态设置
                if (size === "auto")
                {
                    // 大尺寸
                    if (this.size === "large")
                    {
                        size = 18;
                    }
                    // 普通尺寸
                    if (this.size === "normal")
                    {
                        size = 16;
                    }
                    // 小尺寸
                    else if (this.size === "small")
                    {
                        size = 14;
                    }
                    // 超小尺寸
                    else if (this.size === "mini")
                    {
                        size = 12;
                    }
                }

                return size;
            },
            // 获取前缀文字大小
            getPrefixTextSize(): string | number
            {
                let size = this.prefixTextSize;

                // 如果为auto，则根据当前尺寸动态设置
                if (size === "auto")
                {
                    // 大尺寸
                    if (this.size === "large")
                    {
                        size = 18;
                    }
                    // 普通尺寸
                    if (this.size === "normal")
                    {
                        size = 16;
                    }
                    // 小尺寸
                    else if (this.size === "small")
                    {
                        size = 14;
                    }
                    // 超小尺寸
                    else if (this.size === "mini")
                    {
                        size = 12;
                    }
                }

                return size;
            },
            // 获取后缀文字大小
            getSuffixTextSize(): string | number
            {
                let size = this.suffixTextSize;

                // 如果为auto，则根据当前尺寸动态设置
                if (size === "auto")
                {
                    // 大尺寸
                    if (this.size === "large")
                    {
                        size = 18;
                    }
                    // 普通尺寸
                    if (this.size === "normal")
                    {
                        size = 16;
                    }
                    // 小尺寸
                    else if (this.size === "small")
                    {
                        size = 14;
                    }
                    // 超小尺寸
                    else if (this.size === "mini")
                    {
                        size = 12;
                    }
                }

                return size;
            },
            // 获取清除按钮状态
            getClearStatus(): boolean
            {
                return this.clearable && this.isFocus && this.inputValue !== "" && !this.disabled && !this.readonly;
            }
        },
        // 方法
        methods: {
            // 键盘输入时触发事件
            inputHandler(event: Record<string, any>): void
            {
                // 缓存当前值
                this.inputValue = event.detail?.value;

                // 触发内容变化事件方法
                this.valueChange();

                // 阻止冒泡
                this.stop && this.stopPropagation(event);

                // 阻止事件默认行为
                this.prevent && this.preventDefault(event);
            },
            // 获取焦点时触发事件
            focusHandler(event: Record<string, any>): void
            {
                // 设置获取焦点
                this.isFocus = true;

                // 触发获取焦点事件
                this.$emit("focus", this.getOutputValue());

                // 阻止冒泡
                this.stop && this.stopPropagation(event);

                // 阻止事件默认行为
                this.prevent && this.preventDefault(event);
            },
            // 失去焦点时触发事件
            blurHandler(event: Record<string, any>): void
            {
                // H5端的blur会先于点击清除控件的点击click事件触发，导致focus瞬间为false，从而隐藏了清除控件而无法被点击到
                asyncFn(() =>
                {
                    this.isFocus = false;
                }, 180).finally(() =>
                {
                });

                // 触发失去焦点事件
                this.$emit("blur", this.getOutputValue());

                // 阻止冒泡
                this.stop && this.stopPropagation(event);

                // 阻止事件默认行为
                this.prevent && this.preventDefault(event);
            },
            // 键盘完成时触发事件
            confirmHandler(event: Record<string, any>): void
            {
                // 触发键盘完成事件
                this.$emit("confirm", this.getOutputValue());

                // 阻止冒泡
                this.stop && this.stopPropagation(event);

                // 阻止事件默认行为
                this.prevent && this.preventDefault(event);
            },
            // 键盘高度发生变化时触发事件
            keyboardHeightChangeHandler(event: Record<string, any>): void
            {
                // 触发键盘高度变化事件
                this.$emit("keyboardHeightChange", this.getOutputValue());

                // 阻止冒泡
                this.stop && this.stopPropagation(event);

                // 阻止事件默认行为
                this.prevent && this.preventDefault(event);
            },
            // 点击清除按钮时触发事件
            clearHandler(): void
            {
                // 清空当前值
                this.inputValue = "";

                // 触发内容变化事件方法
                this.valueChange();

                // 触发清除事件
                this.$emit("clear", "");
            },
            // 内容发生变化时的处理函数
            valueChange(): void
            {
                this.$nextTick(() =>
                {
                    // 当前输出的值
                    const outputValue = this.getOutputValue();

                    // 触发输入事件
                    this.$emit("input", outputValue);

                    // 触发双向绑定事件
                    this.$emit("update:value", outputValue);
                });
            },
            // 输出值的转化
            getOutputValue(): string | number | null
            {
                let value: string | number | null = this.inputValue;

                // 判断输出值的类型
                if (this.outputType === "number")
                {
                    // 判断输入的是否满足转化为number类型
                    if (!isNaN(Number(value)))
                    {
                        if (value)
                        {
                            value = Number(value);
                        }
                        else
                        {
                            value = null;
                        }
                    }
                    else
                    {
                        throw new Error("输入的值无法转化为number类型");
                    }
                }
                else
                {
                    // 是否trim
                    if (this.trim)
                    {
                        value = value.toString().trim();
                    }
                    else
                    {
                        value = value.toString();
                    }
                }

                return value;
            }
        }
    };
</script>

<template>
    <!-- 输入框组件 -->
    <view
        :class="[
            customClass,
            bemClass
        ]"
        :name="name"
        :style="[
            customStyle,
            {'--custom-input-radius': getRadius},
            {'--custom-input-background-color': backgroundColor},
            {'--custom-input-disabled-background-color': disabledColor},
            {'--custom-input-color': color},
            {'--custom-input-font-size': getFontSize},
            {'--custom-input-text-align': textAlign},
            {'--custom-input-border-color': borderColor}
        ]"
    >
        <!-- 前缀 -->
        <view
            v-if="prefixIcon || prefixText || $slots.prefix"
            class="prefix"
        >
            <!-- 前缀图标 -->
            <u-icon
                v-if="prefixIcon"
                :color="prefixIconColor"
                :custom-style="prefixIconStyle"
                :icon="prefixIcon"
                :size="getPrefixIconSize"
            />
            <!-- // 前缀图标 -->

            <!-- 前缀文字 -->
            <u-text
                v-if="prefixText"
                :color="prefixTextColor"
                :custom-style="prefixTextStyle"
                :font-size="getPrefixTextSize"
                :text="prefixText"
            />
            <!-- //前缀文字 -->

            <!-- 自定义前缀插槽 -->
            <view
                v-if="$slots.prefix"
                class="custom-prefix-slots"
            >
                <slot name="prefix" />
            </view>
            <!-- //自定义前缀插槽 -->
        </view>
        <!-- //前缀 -->

        <!-- 输入框 -->
        <view class="input-wrapper">
            <input
                :adjust-position="adjustPosition"
                :always-embed="alwaysEmbed"
                :auto-blur="autoBlur"
                :confirm-hold="confirmHold"
                :confirm-type="confirmType"
                :cursor="cursor"
                :cursor-color="cursorColor"
                :cursor-spacing="cursorSpacing"
                :disabled="disabled || readonly"
                :focus="autoFocus"
                :hold-keyboard="holdKeyboard"
                :ignore-composition-event="ignoreCompositionEvent"
                :inputmode="inputMode"
                :maxlength="maxlength"
                :password="password"
                :placeholder="placeholder"
                :placeholder-class="placeholderClass"
                :placeholder-style="placeholderStyle"
                :selection-end="selectionEnd"
                :selection-start="selectionStart"
                :type="type"
                :value="inputValue"
                class="input"
                @blur="blurHandler"
                @confirm="confirmHandler"
                @focus="focusHandler"
                @input="inputHandler"
                @keyboardheightchange="keyboardHeightChangeHandler"
            >
        </view>
        <!-- //输入框 -->

        <!-- 清除按钮 -->
        <view
            v-if="getClearStatus"
            class="clear"
            @tap.stop="clearHandler"
        >
            <u-icon
                :size="10"
                color="#fff"
                icon="close"
            />
        </view>
        <!-- //清除按钮 -->

        <!-- 后缀 -->
        <view
            v-if="suffixIcon || suffixText || $slots.suffix"
            class="suffix"
        >
            <!-- 后缀图标 -->
            <u-icon
                v-if="suffixIcon"
                :color="suffixIconColor"
                :custom-style="suffixIconStyle"
                :icon="suffixIcon"
                :size="getSuffixIconSize"
            />
            <!-- //后缀图标 -->

            <!-- 后缀文字 -->
            <u-text
                v-if="suffixText"
                :color="suffixTextColor"
                :custom-style="suffixTextStyle"
                :font-size="getSuffixTextSize"
                :text="suffixText"
            />
            <!-- //后缀文字 -->

            <!-- 自定义后缀插槽 -->
            <view
                v-if="$slots.suffix"
                class="custom-suffix-slots"
            >
                <slot name="suffix" />
            </view>
            <!-- //自定义后缀插槽 -->
        </view>
        <!-- //后缀 -->
    </view>
    <!-- //输入框组件 -->
</template>

<style lang="scss" scoped>
    $u-input-wrapper-border-color: #c8c9cc !default;
    $u-input-clear-background-color: #c6c7cb !default;

    .u-input
    {
        display: flex;
        align-items: center;
        justify-content: space-between;
        box-sizing: border-box;
        border-radius: var(--custom-input-radius);
        background-color: var(--custom-input-background-color);

        // 输入框
        .input-wrapper
        {
            flex: 1;

            // 输入控件
            .input
            {
                font-size: var(--custom-input-font-size);
                margin: 0;
                padding: 0;
                text-align: var(--custom-input-text-align);
                color: var(--custom-input-color, $theme-main-text-color);
                border: none;
                outline: none;
                background: none;
                font-variant-numeric: tabular-nums;
            }

            // placeholderStyle样式名称
            :deep(.input-placeholder)
            {
                font-size: var(--custom-input-font-size);
                font-weight: normal;
                color: $theme-para-text-color;
            }
        }

        // 清除按钮
        .clear
        {
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 50%;
            background-color: $u-input-clear-background-color;
        }

        // 前缀&后缀
        .prefix, .suffix
        {
            display: flex;
            align-items: center;
        }

        // large尺寸
        &-large
        {
            height: $size-large;
            padding: 0 10px;

            // 清除按钮
            .clear
            {
                width: 20px;
                height: 20px;
                margin-left: 8px;
            }

            // 前缀
            .prefix
            {
                margin-right: 8px;
            }

            // 后缀
            .suffix
            {
                margin-left: 8px;
            }
        }

        // normal尺寸
        &-normal
        {
            height: $size-normal;
            padding: 0 9px;

            // 清除按钮
            .clear
            {
                width: 20px;
                height: 20px;
                margin-left: 6px;
            }

            // 前缀
            .prefix
            {
                margin-right: 6px;
            }

            // 后缀
            .suffix
            {
                margin-left: 6px;
            }
        }

        // small尺寸
        &-small
        {
            height: $size-small;
            padding: 0 8px;

            // 清除按钮
            .clear
            {
                width: 16px;
                height: 16px;
                margin-left: 4px;
            }

            // 前缀
            .prefix
            {
                margin-right: 4px;
            }

            // 后缀
            .suffix
            {
                margin-left: 4px;
            }
        }

        // 超小尺寸
        &-mini
        {
            height: $size-mini;
            padding: 0 6px;

            // 清除按钮
            .clear
            {
                width: 14px;
                height: 14px;
                margin-left: 2px;
            }

            // 前缀
            .prefix
            {
                margin-right: 2px;
            }

            // 后缀
            .suffix
            {
                margin-left: 2px;
            }
        }

        // 圆角按钮
        &-square
        {
            // 超小尺寸圆角
            &.u-input-radius-mini
            {
                border-radius: $border-radius-mini;
            }

            // 小尺寸圆角
            &.u-input-radius-small
            {
                border-radius: $border-radius-small;
            }

            // 普通尺寸圆角
            &.u-input-radius-normal
            {
                border-radius: $border-radius-normal;
            }

            // 大尺寸圆角
            &.u-input-radius-large
            {
                border-radius: $border-radius-large;
            }
        }

        // 半圆按钮
        &-circle
        {
            border-radius: 100px;
        }

        // 四边框
        &-border-surround
        {
            border: 1px solid var(--custom-input-border-color, $u-input-wrapper-border-color);
        }

        // 底部边框
        &-border-bottom
        {
            border-bottom: 1px solid var(--custom-input-border-color, $u-input-wrapper-border-color);
            border-radius: 0 !important;
        }

        // 无边框
        &-border-none
        {
            border: none;
            padding: 0;
        }

        // 禁用
        &-disabled
        {
            pointer-events: none;
            background-color: var(--custom-input-disabled-background-color);

            // 输入框
            .input-wrapper
            {
                // 输入控件
                .input
                {
                    opacity: 0.2;
                }
            }
        }
    }
</style>